"""多线程的同步机制-Semaphore（信号对象）： 信号量同步基于内部计数器，每调用一次acquire()，计数器减1；每调用一次release()，计数器加1.当计数器为0时，acquire()调用被阻塞。

acquire(blocking=True, timeout=None)获取信号。

当blocking=True时：如果调用时计数器大于零，则将其减1并立即返回。如果在调用时计数器为零，则阻塞并等待，直到其他线程调用release()使其大于零。这是通过适当的互锁来完成的，因此如果多个acquire()被阻塞，release()将只唤醒其中一个，这个过程会随机选择一个，因此不应该依赖阻塞线程的被唤醒顺序。返回值为True。
当blocking=False时，不会阻塞。如果调用acquire()时计数器为零，则会立即返回False.
如果设置了timeout参数，它将阻塞最多timeout秒。如果在该时间段内没有获取锁，则返回False，否则返回True。
release() 释放信号，使计数器递增1。当计数器为零并有另一个线程等待计数器大于零时，唤醒该线程。

互斥锁，同时只允许一个线程更改数据，而Semaphore是同时允许一定数量的线程更改数据 ，比如厕所有3个坑，那最多只允许3个人上厕所，后面的人只能等里面有人出来了才能再进去。
"""
from threading import Semaphore, currentThread
from concurrent.futures import ThreadPoolExecutor
import time, random


def task():
    sm.acquire()
    print('%s is running!' % currentThread().getName())
    time.sleep(random.randint(1, 3))
    print('%s is end!' % currentThread().getName())
    sm.release()


if __name__ == '__main__':
    sm = Semaphore(5)  # 每次允许5个线程运行
    with ThreadPoolExecutor(max_workers=10) as executor:
        for i in range(10):
            executor.submit(task)
